{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "4c6ea9d0",
   "metadata": {},
   "source": [
    "结合 LangChain v0.3 官方文档 [Vector Stores 章节](https://python.langchain.com/docs/how_to/#vector-stores)，本文将从背景知识、核心概念、LangChain 集成特性、通用使用流程和实战示例五个维度，全面解析 Vector Stores 组件，帮助你理解其在检索增强生成（RAG）中的核心作用。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ba2fc428",
   "metadata": {},
   "source": [
    "# 一、背景与核心概念：为什么需要 Vector Stores？\n",
    "在深入 LangChain 的实现前，首先要明确 Vector Stores 的本质的解决的核心问题 —— 它是连**接 Embedding 模型与检索任务的 “桥梁”**，是 RAG（Retrieval-Augmented Generation，检索增强生成）架构的关键基础设施。\n",
    "\n",
    "## 1.1 核心痛点：大模型的 “知识局限” 与 “高效检索需求”\n",
    "大模型（如 DeepSeek）存在两大核心局限，需要 Vector Stores 解决：\n",
    "\n",
    "- 上下文窗口有限：大模型无法直接处理超长文本（如万字文档、多文件集合），必须将文本拆分为小块后，仅选择 “与查询相关” 的片段输入模型。\n",
    "- 知识静态且私有：大模型的训练数据截止到特定时间（如 DeepSeek 某版本截止到 2024 年），无法获取实时 / 最新知识；同时无法直接访问私有数据（如企业内部文档）。\n",
    "\n",
    "要解决这些问题，需要先将文本转换为向量（Embedding）（通过 Embedding 模型），再通过相似性检索找到与用户查询最相关的文本片段 —— 而 Vector Stores 正是为 “高效存储向量” 和 “快速相似性检索” 设计的组件。\n",
    "\n",
    "## 1.2 什么是 Vector Stores？\n",
    "Vector Stores（向量存储 / 向量数据库）是专门用于存储文本 Embedding 向量及对应文本片段（和元数据） 的工具，核心能力是：\n",
    "\n",
    "- 存储：将 Embedding 向量与文本片段（如分割后的文档块）、元数据（如文档来源、创建时间、作者）关联存储。\n",
    "- 检索：给定查询的 Embedding 向量，快速返回 “向量相似度最高” 的 Top K 个文本片段（即 “相似性检索”）。\n",
    "\n",
    "## 1.3 相似性检索的核心算法\n",
    "Vector Stores 的检索能力依赖于 “向量相似度计算”，LangChain 默认支持主流算法，无需手动实现：\n",
    "\n",
    "算法|\t核心逻辑|\t适用场景|\n",
    "|:--|:--|:--|\n",
    "余弦相似度|\t计算两向量夹角的余弦值（范围 [-1,1]，越近越相关）|\t文本语义相似性匹配（最常用）\n",
    "欧氏距离|\t计算两向量在空间中的直线距离（值越小越相关）|\t低维向量场景\n",
    "曼哈顿距离|\t计算两向量在各维度上的绝对差之和（值越小越相关）|\t高维稀疏向量场景\n",
    "\n",
    "## 1.4 Vector Stores 在 LangChain 中的定位\n",
    "LangChain 不重复造轮子（不自研向量数据库），而是对主流 Vector Stores 进行标准化封装，提供统一的接口（如 add_documents、similarity_search、as_retriever），让开发者无需关注不同向量数据库的底层差异，只需通过 LangChain 接口即可快速集成。\n",
    "\n",
    "其在 LangChain 流程中的位置如下：\n",
    "\n",
    "文档加载（Document Loaders） → 文本分割（Text Splitters） → Embedding 转换 → Vector Stores 存储与检索 → Retriever 接口 → RAG Chain（如 RetrievalQA）"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "780b5751",
   "metadata": {},
   "source": [
    "# 二、LangChain Vector Stores 的核心特性\n",
    "LangChain v0.3 对 Vector Stores 的集成做了优化（部分组件拆分为独立包），核心特性如下：\n",
    "\n",
    "## 2.1 标准化接口：统一所有 Vector Stores 的使用方式\n",
    "无论选择哪种 Vector Stores（如 Chroma、FAISS、Pinecone），LangChain 都提供一致的核心方法，降低学习成本：\n",
    "\n",
    "核心方法|\t功能描述|\n",
    "|:--|:--|\n",
    "from_documents(docs, embeddings)|\t静态方法：直接将分割后的文档（docs）通过 Embedding 模型转换为向量并存储，返回 Vector Store 实例\n",
    "add_documents(docs)\t|将文档转换为向量并添加到已存在的 Vector Store 中\n",
    "similarity_search(query, k=4)|\t给定查询文本（query），返回 Top k 个最相似的文档片段\n",
    "similarity_search_with_score(query, k=4)|\t返回相似文档及对应的相似度分数（分数越高 / 距离越小，相关性越强）\n",
    "as_retriever()|\t将 Vector Store 转换为 LangChain 标准的 Retriever 接口，用于衔接 Chain\n",
    "similarity_search_with_filter(query, filter={})|\t结合元数据过滤（如 “仅检索 2024 年后的文档”）进行相似性检索\n",
    "\n",
    "## 2.2 支持主流 Vector Stores：覆盖本地与生产场景\n",
    "LangChain 支持 20+ 主流 Vector Stores，可根据场景选择（本地开发用轻量型，生产用托管型）：\n",
    "\n",
    "Vector Store|\t类型|\t核心特点|\t适用场景|\t安装依赖（LangChain v0.3）\n",
    "|:--|:--|:--|:--|:--|\n",
    "Chroma|\t本地轻量|\t开源、无服务依赖、支持持久化、API 简洁\t|本地开发、快速原型验证\t|pip install langchain-chroma\n",
    "FAISS|\t本地高效|\tFacebook 开源、检索速度快、支持高维向量\t|本地大数据量检索\t|pip install langchain-faiss-cpu（CPU 版）/ langchain-faiss-gpu（GPU 版）\n",
    "Pinecone|\t托管云服务|\t全托管、高可用、支持动态扩容、适合大规模生产\t|企业级生产环境、海量数据\t|pip install langchain-pinecone pinecone-client\n",
    "Weaviate|\t开源 / 托管\t|支持语义搜索、结构化过滤、Graph 检索\t|复杂过滤场景、知识图谱集成\t|pip install langchain-weaviate weaviate-client\n",
    "Qdrant|\t本地 / 托管|\t支持向量索引、地理空间检索、元数据过滤\t|多模态检索（文本 + 图像）\t|pip install langchain-qdrant qdrant-client\n",
    "\n",
    "## 2.3 与 Retriever 无缝集成：衔接 RAG 流程\n",
    "LangChain 中，Retriever 是 “检索能力” 的标准接口（定义了 get_relevant_documents(query) 方法），而 Vector Stores 通过 as_retriever() 方法可直接转换为 Retriever，无需额外适配即可接入 RAG Chain（如 RetrievalQA、ConversationalRetrievalChain）。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "791b9fd4",
   "metadata": {},
   "source": [
    "# 三、Vector Stores 通用使用流程\n",
    "无论选择哪种 Vector Stores，核心流程都可分为 5 步，以 “本地文档检索” 为例：\n",
    "\n",
    "- 步骤 1：加载文档：用 Document Loaders 加载本地 / 远程文档（如 TXT、PDF）。\n",
    "- 步骤 2：分割文档：用 Text Splitters 将长文档拆分为小块（避免超出 Embedding 模型长度限制）。\n",
    "- 步骤 3：初始化 Embedding 模型：将文本转换为向量（如 DeepSeek Embedding、OpenAI Embedding）。\n",
    "- 步骤 4：初始化 Vector Store 并存储向量：通过 from_documents 或 add_documents 存储分割后的文档向量。\n",
    "- 步骤 5：执行检索或接入 RAG：用 similarity_search 直接检索，或用 as_retriever 接入 Chain。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9434a83d",
   "metadata": {},
   "source": [
    "# 四、FAISS 示例\n",
    "FAISS（Facebook AI Similarity Search）是 Facebook 开源的高效向量检索库，支持百万级向量的快速检索，适合本地处理大数据量文档（如数千篇文章）。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "93328ef4",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "=== FAISS 过滤后检索结果 ===\n",
      "内容：人工智能（AI）是当前科技领域的核心趋势之一。它通过模拟人类智能，实现了图像识别、自然语言处理、自动驾驶等多个领域的突破。\n",
      "\n",
      "在自然语言处理（NLP）领域，大语言模型（LLM）是关键技术。例如 DeepSeek、GPT-4 等模型，能理解和生成人类级别的文本，广泛应用于聊天机器人、内容创作、代码生成... | 来源：../../example.txt\n",
      "=== 相关文档 1 ===\n",
      "内容：人工智能（AI）是当前科技领域的核心趋势之一。它通过模拟人类智能，实现了图像识别、自然语言处理、自动驾驶等多个领域的突破。\n",
      "\n",
      "在自然语言处理（NLP）领域，大语言模型（LLM）是关键技术。例如 DeepSeek、GPT-4 等模型，能理解和生成人类级别的文本，广泛应用于聊天机器人、内容创作、代码生成等场景。\n",
      "\n",
      "然而，LLM 存在上下文窗口限制——无法处理超过窗口长度的文本。因此，Text Spli...\n",
      "来源：../../example.txt\n",
      "页码：未知\n",
      "\n"
     ]
    }
   ],
   "source": [
    "import os\n",
    "\n",
    "# 1. 加载环境变量\n",
    "api_base = os.getenv(\"OPENAI_API_BASE\")\n",
    "api_key = os.getenv(\"OPENAI_API_KEY\")\n",
    "db_path = \"../../faiss_db\"\n",
    "emb_model_path = \"../../embed_model/bge-large-zh-v1.5\"\n",
    "\n",
    "# 2. 文档加载（以本地 TXT 文件为例）\n",
    "from langchain_community.document_loaders import TextLoader\n",
    "loader = TextLoader(\"../../example.txt\", encoding=\"utf-8\")\n",
    "documents = loader.load()  # 加载文档，返回 [Document] 列表\n",
    "\n",
    "# 3. 文本分割（使用之前学的 Text Splitter）\n",
    "from langchain_text_splitters import RecursiveCharacterTextSplitter\n",
    "text_splitter = RecursiveCharacterTextSplitter(\n",
    "    chunk_size = 500,          # 每个文档块的字符数\n",
    "    chunk_overlap = 50,        # 块之间的重叠字符数（保持上下文连贯）\n",
    "    length_function = len      # 长度计算方式（默认按字符数）\n",
    ")\n",
    "split_docs = text_splitter.split_documents(documents)  # 分割为文档块\n",
    "\n",
    "# 4. 初始化 Embedding 模型（将文本转换为向量）\n",
    "from langchain_huggingface import HuggingFaceEmbeddings\n",
    "embeddings = HuggingFaceEmbeddings(\n",
    "    model_name = emb_model_path,\n",
    "    model_kwargs = {\"device\": \"cpu\"},  # 可指定\"cuda\"使用GPU,\n",
    "    encode_kwargs = {\"normalize_embeddings\": True}  # 归一化向量，提升相似度计算准确性\n",
    ")\n",
    "\n",
    "# 5. 初始化 FAISS 并存储向量（支持持久化）\n",
    "from langchain_community.vectorstores import FAISS\n",
    "\n",
    "# 判断目录是否存在\n",
    "if not os.path.exists(db_path):\n",
    "    # 方式 1：从文档块直接创建 FAISS（自动转换向量并存储）\n",
    "    vector_store = FAISS.from_documents(\n",
    "        documents = split_docs,    # 分割后的文档块\n",
    "        embedding = embeddings,    # Embedding 模型\n",
    "    )\n",
    "\n",
    "    # 方式 2：持久化到本地（下次直接加载，无需重新生成向量）\n",
    "    vector_store.save_local(db_path)  # 保存到 ../faiss_db 目录\n",
    "else:\n",
    "    # 方式 3：加载已持久化的 FAISS\n",
    "    vector_store = FAISS.load_local(\n",
    "        db_path,\n",
    "        embeddings,\n",
    "        allow_dangerous_deserialization=True  # 允许反序列化（本地使用安全）\n",
    "    )\n",
    "\n",
    "# 6. 相似性检索（支持元数据过滤）\n",
    "query = \"RAG的核心组件是什么?\"\n",
    "# 基础检索\n",
    "retrieved_docs = vector_store.similarity_search(query, k=3)\n",
    "\n",
    "# 带元数据过滤的检索（例如：仅检索来源为 \"tech_doc.txt\" 的文档）\n",
    "filtered_docs = vector_store.similarity_search(\n",
    "    query,\n",
    "    k = 3,\n",
    "    #filter = {\"source\": \"tech_doc.txt\"}  # 元数据过滤条件\n",
    ")\n",
    "\n",
    "print(\"\\n=== FAISS 过滤后检索结果 ===\")\n",
    "for doc in filtered_docs:\n",
    "    print(f\"内容：{doc.page_content[:150]}... | 来源：{doc.metadata['source']}\")\n",
    "\n",
    "#8. 转换为 Retriever 接入 RAG Chain\n",
    "retriever = vector_store.as_retriever(search_kwargs={\"k\": 2})  # 每次检索 Top 2\n",
    "# 执行检索，可以简单的理解 invoke 是对 vector_store.similarity_search 的简单封装\n",
    "relevant_docs = retriever.invoke(query)\n",
    "\n",
    "# 打印结果（遍历 Document 列表，输出内容和元数据）\n",
    "for i, doc in enumerate(relevant_docs, 1):\n",
    "    print(f\"=== 相关文档 {i} ===\")\n",
    "    print(f\"内容：{doc.page_content[:200]}...\")  # 只打印前 200 字符\n",
    "    print(f\"来源：{doc.metadata.get('source', '未知')}\")  # 元数据中的文档来源\n",
    "    print(f\"页码：{doc.metadata.get('page', '未知')}\\n\")  # 若为 PDF 文档，会有页码\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "83cc2204",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "=== RAG 回答结果 ===\n",
      "回答：根据提供的上下文，RAG（Retrieval-Augmented Generation）的核心组件是 **Text Splitters（文本拆分器）**。它的作用是将长文本拆分为多个语义完整的小片段（chunk），以克服大语言模型（LLM）的上下文窗口限制，确保文本能够被有效处理并用于检索或生成任务。\n",
      "源文档数量：1\n"
     ]
    }
   ],
   "source": [
    "# # 初始化 DeepSeek LLM\n",
    "from langchain_openai import ChatOpenAI\n",
    "llm = ChatOpenAI(\n",
    "    model_name = \"deepseek-chat\",  # 或 deepseek-coder 用于代码生成\n",
    "    openai_api_base = api_base,\n",
    "    openai_api_key = api_key,\n",
    "    temperature = 0  # 控制输出随机性（0 表示更严谨）\n",
    ")\n",
    "\n",
    "# 构建 RAG Chain（RetrievalQA）\n",
    "from langchain.chains import RetrievalQA\n",
    "qa_chain = RetrievalQA.from_chain_type(\n",
    "    llm=llm,\n",
    "    chain_type=\"stuff\",  # 简单策略：将所有检索文档拼接传入模型\n",
    "    retriever=retriever,\n",
    "    return_source_documents=True  # 返回检索到的源文档（方便溯源）\n",
    ")\n",
    "\n",
    "# 执行 RAG 查询\n",
    "rag_result = qa_chain.invoke(query)\n",
    "print(\"\\n=== RAG 回答结果 ===\")\n",
    "print(f\"回答：{rag_result['result']}\")\n",
    "print(f\"源文档数量：{len(rag_result['source_documents'])}\")"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "venv",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
